#ifndef DYNAMIC_LIBRARY_H
#define DYNAMIC_LIBRARY_H

#ifdef WIN32
  #include <windows.h>
#else
  #include <dlfcn.h>
#endif

#include <sstream>
#include <iostream>
#include <string>

class DynamicLibrary
{
public:

	static DynamicLibrary* load( const std::string & path, std::string &errorString )
	{
		if (path.empty())
		{
			errorString = "Empty path.";
			return NULL;
		}
		
		void* handle = NULL;
		
		#ifdef WIN32
			handle = ::LoadLibraryA(path.c_str());
			if (handle == NULL)
			{
				DWORD errorCode = ::GetLastError();
				std::stringstream ss;
				ss << std::string("LoadLibrary( \"") << path
				   << std::string("\" ) failed. ErrorCode: ")
				   << errorCode;
				errorString = ss.str();
				//bb added:
				return NULL;
			}
		#else
			handle = ::dlopen(path.c_str(), RTLD_NOW);
			if (!handle) 
			{
			  std::string dlErrorString;
			  const char *zErrorString = ::dlerror();
			  if (zErrorString)
			    dlErrorString = zErrorString;
			  errorString += "Failed to load \"" + path + '"';
			  if(dlErrorString.size())
			    errorString += ": " + dlErrorString;
			  return NULL;
			}
		#endif
		
		return new DynamicLibrary(handle);
	}
	
	~DynamicLibrary()
	{
		if (handle_)
		{
			#ifndef WIN32
				::dlclose(handle_);
			#else
				::FreeLibrary((HMODULE)handle_);
			#endif
		}
	}
  
	void* getSymbol( const std::string& symbol )
	{
		if (!handle_)
			return NULL;
		
		#ifdef WIN32
			return (void*) ::GetProcAddress((HMODULE)handle_, symbol.c_str());
		#else
			return ::dlsym(handle_, symbol.c_str());
		#endif
	}

private:
  DynamicLibrary();
  DynamicLibrary(void* handle) : handle_(handle)    {}
  DynamicLibrary(const DynamicLibrary &);
  
private:
  void* handle_;
};

#endif //DYNAMIC_LIBRARY_H
